/*
 * Copyright (C) 2008 The Android Open Source Project
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/**
 * @defgroup fcntl Fcntl
 * @ingroup libc
 */

#ifndef _FCNTL_H
#define _FCNTL_H

#include <sys/cdefs.h>
#include <sys/types.h>
#ifndef __LITEOS__
#include <linux/fadvise.h>
#include <linux/fcntl.h>
#include <linux/stat.h>
#include <linux/uio.h>
#else
#include <liteos/fcntl.h>
#include <liteos/stat.h>
#include <liteos/uio.h>
#endif

#ifndef __LITEOS__
#if defined(__USE_GNU) || defined(__USE_BSD)
#include <bits/lockf.h>
#endif
#endif

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */


#ifdef __LP64__
/* LP64 kernels don't have F_*64 defines because their flock is 64-bit. */
#define F_GETLK64  F_GETLK
#define F_SETLK64  F_SETLK
#define F_SETLKW64 F_SETLKW
#endif

#define O_ASYNC FASYNC
#define O_RSYNC O_SYNC

#define SPLICE_F_MOVE 1
#define SPLICE_F_NONBLOCK 2
#define SPLICE_F_MORE 4
#define SPLICE_F_GIFT 8

#define SYNC_FILE_RANGE_WAIT_BEFORE 1
#define SYNC_FILE_RANGE_WRITE 2
#define SYNC_FILE_RANGE_WAIT_AFTER 4

/**
* @ingroup fcntl
*
* @par Description:
* Create a new file or rewrite an existing one.
* @param  path  [IN] Path of the file which need to be checked.
* @param  mode  [IN] Describes the permissions of the file, should be an integer type.
* (For example: 0666, 0777)
* @attention
* <ul>
* <li>None.</li>
* </ul>
*
* @retval #0  Upon successful completion.
* @retval #-1 Failed and set errno to indicate the error.
*
* @par Errors
* <ul>
* <li>Refer to open.</li>
* </ul>
*
* @par Dependency:
* <ul><li>fcntl.h</li></ul>
* @see None
* @since Huawei LiteOS V100R001C00
*/
extern int creat(const char* path, mode_t mode);
extern int creat64(const char*, mode_t);

/**
* @ingroup fcntl
*
* @par Description:
* The fcntl() function shall perform the operations described below on open files.
* @param  fd  [IN] A file descriptor.
* @param  cmd [IN] The available values for cmd are defined in <arm-generic/fcntl.h>, refer to the attention.
* @param  ... [IN] See the usage of this parameter in attention.
* @attention
* <ul>
* <li><b>F_DUPFD</b>: Return a new file descriptor which shall be the lowest numberedavailable (not already open) file
* descriptor greater than or equal to the third argument, arg, taken as an integer of type int. The new file descriptor
* shall refer to the same open file description as the original file descriptor, and shall share any locks.
* The FD_CLOEXEC flag associated  with the new file descriptor shall be cleared to keep the file open across calls to
* one of the exec functions.</li>
* <li><b>F_GETFD</b>: Not support.</li>
* <li><b>F_SETFD</b>: Not support.</li>
* <li><b>F_GETFL</b>: Get the file status flags and file access modes, defined in <arm-generic/fcntl.h>,for the file
* description associated with fd. The file access modes can be extracted from the return value using the mask O_ACCMODE,
* which is defined  in <arm-generic/fcntl.h>. File status flags and file access modes are associated with the file
* description and do not affect other file descriptors that refer to the same file with different open file descriptions
* .</li>
* <li><b>F_SETFL</b>: Set the file status flags, defined in <arm-generic/fcntl.h>, for the file description associated
* with fd from the corresponding  bits in the third argument, arg, taken as type int. Bits corresponding to the file
* access mode and the file creation flags, as defined in <arm-generic/fcntl.h>, that are set in arg shall be ignored.
* If any bits in arg other than those mentioned here are changed by the application, the result is unspecified.</li>
* <li><b>F_GETOWN</b>: Setting this option returns an ebad [EBADF] error.</li>
* <li><b>F_SETOWN</b>: Setting this option returns an ebad [EBADF] error.</li>
* <li><b>F_GETLK</b>: Not support.</li>
* <li><b>F_SETLK</b>: Not support.</li>
* <li><b>F_SETLKW</b>: Not support.</li>
* <li><b>other option</b>: Returns the [EINVAL] error.</li>\n
* Operations on a socket descriptorare as follows:
* <li><b>F_GETFL</b>: If the socket is in non-blocking mode, return O_NONBLOCK.</li>
* <li><b>F_SETFL</b>: If bits in the third argument, arg, only O_NONBLOCK, set the socket to non-blocking mode.</li>
* <li><b>other option</b>: Returns the [EINVAL] error.</li>
* </ul>
*
* @retval #0  Upon successful completion.
* @retval #-1 Failed and set errno to indicate the error.
*
* @par Errors
* <ul>
* <li><b>EBADF</b>: The fd argument is not a valid file descriptor.</li>.
* <li><b>EAGAIN</b>: The file list is NULL.</li>
* <li><b>ENOMEM</b>: Out of memory.</li>
* <li><b>EMFILE</b>: Too many open files.</li>
* <li><b>ENOENT</b>: No such file or directory.</li>
* <li><b>ENOSYS</b>: not support.</li>
* <li><b>ENODEV</b>: No such device.</li>
* <li><b>EINVAL</b>: Invalid argument.</li>
* </ul>
*
* @par Dependency:
* <ul><li>fcntl.h</li></ul>
* @see None
* @since Huawei LiteOS V100R001C00
*/
extern int fcntl(int fd, int cmd, ...);
extern int openat(int, const char*, int, ...);
extern int openat64(int, const char*, int, ...);

/**
* @ingroup fcntl
*
* @par Description:
* The open() function shall establish the connection between a file and a file descriptor.
* It shall create an open file description that refers to a file and a file descriptor that refers to that open file
* description. The file descriptor is used by other I/O functions to refer to that file.
* The file offset used to mark the current position within the file shall be set to the beginning of the file.
* The file status flags and file access modes of the open file description shall be set according to the value of oflag.
* @param  path   [IN] Points to a pathname naming the file.
* @param  oflags [IN] Values for oflag are constructed by a bitwise-inclusive OR of flags from the following list,
* defined in <libc/kernel/asm-generic/fcntl.h>. Applications should specify one of the median values
* (file access patterns) in the value of oflag in the attention description.
* @param  ...    [IN] If the file is opened for creation, description file mode_t mode.
* @attention
* <ul>
* <li><b>O_RDONLY</b>: Open for reading only.</li>
* <li><b>O_RDWR</b>: Open for reading and writing. The result is undefined if this flag is applied to a FIFO.</li>
* <li><b>O_WRONLY</b>: Open for writing only.</li>
* <li><b>O_CREAT</b>: If the file exists, this flag has no effect except as noted under O_EXCL below. Otherwise,
* if O_DIRECTORY is not set the file shall be created as a regular file; the access permission bits of the file mode
* shall be set to the value of the argument following the oflag argument taken as type mode_t.</li>
* <li><b>O_EXCL</b>: If O_CREAT and O_EXCL are set, open() shall fail if the file exists.
* The check for the existence of the file and the creation of the file if it does not exist shall be atomic with
* respect to other threads executing open() naming the same filename in the same directory with O_EXCL and O_CREAT set.
* If O_EXCL and O_CREAT are set, and path names a symbolic link, open() shall fail and set errno to [EEXIST],
* regardless of the contents of the symbolic link. If O_EXCL is set and O_CREAT is not set, the result is undefined
* .</li>
* <li><b>O_NOCTTY</b>: If set and path identifies a terminal device, open() shall not cause the terminal device to
* become the controlling terminal for the process. If path does not identify a terminal device, O_NOCTTY shall be
* ignored.</li>
* <li><b>O_APPEND</b>: If set, the file offset shall be set to the end of the file prior to each write.</li>
* <li><b>O_NONBLOCK</b>: When opening a FIFO with O_RDONLY or O_WRONLY set:
* If O_NONBLOCK is set, an open() for reading-only shall return without delay.
* An open() for writing-only shall return an error if no process currently has the file open for reading.
* If O_NONBLOCK is clear, an open() for reading-only shall block the calling thread until a thread opens the file
* for writing. An open() for writing-only shall block the calling thread until a thread opens the file for reading.</li>
* <li><b>O_TRUNC</b>: If the file exists and is a regular file, and the file is successfully opened O_RDWR or O_WRONLY,
* its length shall be truncated to 0, and the mode and owner shall be unchanged. It shall have no effect on FIFO special
* files or terminal device files. Its effect on other file types is implementation-defined.
* The result of using O_TRUNC without either O_RDWR or O_WRONLY is undefined.</li>
* <li><b>O_DIRECTORY</b>: No support, if set this mode returns error code [EACCES].</li>
* <li><b>O_NOFOLLOW</b>: If path names a symbolic link, fail and set errno to [ENOENT].</li>
* <li><b>O_DIRECT</b>: Not support.</li>
* </ul>
*
* @retval #0  Upon successful completion.
* @retval #-1 Failed and set errno to indicate the error.
*
* @par Errors
* <ul>
* <li><b>EACCES</b>: Permission bits of the file mode do not permit the requested access,
* or search permission is denied on a component of the path prefix.
* In jffs2 file system: set oflags O_DIRECTORY return it.</li>
* <li><b>EINVAL</b>: The path name format is invalid.</li>
* <li><b>ENAMETOOLONG</b>: The length of a component of a pathname is longer than {NAME_MAX}.</li>
* <li><b>ENOENT</b>: O_CREAT is not set and the named file does not exist. Or a directory component in pathname does not
* exist or is a dangling symbolic link. This error code is also returned in the fat file system: no valid FAT volume,
* not find the file, not find the path</li>
* <li><b>ENOMEM</b>: Out of memory.</li>
* <li><b>ENXIO</b>: Inode is invalid or not a "normal" character driver or not a mountpoint.</li>
* <li><b>EMFILE</b>: All file descriptors available to the process are currently open.</li>
* <li><b>EPERM</b>: Get the file structure corresponding to the file descriptor failed.
* In fat file system: This error code is also returned when operation not permitted or access denied due to prohibited
* access or directory full.</li>
* <li><b>EEXIST</b>: O_CREAT and O_EXCL are set, and the named file exists.
* <li><b>EIO</b>: A hard error occurred in the low level disk I/O layer ro the physical drive cannot work or Assertion
* failed.</li>
* <li><b>EROFS</b>: The named file resides on a read-only file system and either O_WRONLY, O_RDWR, O_CREAT
* (if the file does not exist), or O_TRUNC is set in the oflag argument.</li>
* <li><b>ENOSPC</b>: The directory or file system that would contain the new file cannot be expanded,
* the file does not exist, and O_CREAT is specified.</li>
* <li><b>ENFILE</b>: The maximum allowable number of files is currently open in the system.</li>
* <li><b>EISDIR</b>: The named file is a directory and oflag includes O_WRONLY or O_RDWR, or includes O_CREAT without
* O_DIRECTORY.</li>
* <li><b>ENOTDIR</b>: A component of the path prefix names an existing file that is neither a directory nor a symbolic
* link to a directory; or O_CREAT and O_EXCL are not specified, the path argument contains at least one non-<slash>
* character and ends with one or more trailing <slash> characters, and the last pathname component names an existing
* file that is neither a directory nor a symbolic link to a directory; or the path
* argument resolves to a non-directory file.</li>
* <li><b>EBUSY</b>: The operation is rejected according to the file sharing policy.</li>
* <li><b>ENODEV</b>: No such device.</li>
* <li><b>ENOTEMPTY</b>: Directory not empty.</li>
* <li><b>ELOOP</b>: Too many symbolic links encountered.</li>
* <li><b>EFAULT</b>: Bad address.</li>
* </ul>
*
* @par Dependency:
* <ul><li>fcntl.h</li></ul>
* @see None
* @since Huawei LiteOS V100R001C00
*/
extern int open(const char* path, int oflags, ...);

/**
* @ingroup fcntl
*
* @par Description:
* The open() function shall establish the connection between a file and a file descriptor.
* It shall create an open file description that refers to a file and a file descriptor that refers to that open file
* description. The file descriptor is used by other I/O functions to refer to that file.
* The file offset used to mark the current position within the file shall be set to the beginning of the file.
* The file status flags and file access modes of the open file description shall be set according to the value of oflag.
* @param  __path [IN] path of the file which need to be checked.
* @param  __oflags [IN] Values for oflag are constructed by a bitwise-inclusive OR of flags from the following list,
* defined in <libc/kernel/asm-generic/fcntl.h>. Applications should specify one of the median values
* (file access patterns) in the value of oflag in the attention description.
* @param  ...    [IN] If the file is opened for creation, description file mode_t mode. The default value is 0666.
* @attention
* <ul>
* <li>Refer to open.</li>
* </ul>
*
* @retval #0  Upon successful completion.
* @retval #-1 Failed and set errno to indicate the error.
*
* @par Errors
* <ul>
* <li>Refer to open.</li>
* </ul>
*
* @par Dependency:
* <ul><li>fcntl.h</li></ul>
* @see None
* @since Huawei LiteOS V100R001C00
*/
extern int open64(const char* __path, int __oflag, ...);
extern ssize_t splice(int, off64_t*, int, off64_t*, size_t, unsigned int);
extern ssize_t tee(int, int, size_t, unsigned int);
extern int unlinkat(int, const char*, int);
extern ssize_t vmsplice(int, const struct iovec*, size_t, unsigned int);

#if defined(__USE_FILE_OFFSET64)
extern int fallocate(int, int, off_t, off_t) __RENAME(fallocate64);
extern int posix_fadvise(int, off_t, off_t, int) __RENAME(posix_fadvise64);
extern int posix_fallocate(int, off_t, off_t) __RENAME(posix_fallocate);
#else

/**
* @ingroup fcntl
*
* @par Description:
* The fallocate() function shall ensure that any required storage for regular file data starting at offset and
* continuing for len bytes is allocated on the file system storage media.
* @param fd     [IN] File descriptor.
* @param mode   [IN] Extend size.
* @param offset [IN] File offset.
* @param len    [IN] The length starting from the file offset.
* @attention
* <ul>
* <li>None.</li>
* </ul>
*
* @retval #0  Upon successful completion.
* @retval #-1 Failed and set errno to indicate the error.
*
* @par Errors
* <ul>
* <li><b>EINVAL</b>: The len argument or the offset argument is less than zero or greater than INT_MAX,
* or extend size is not equal to FALLOC_FL_KEEP_SIZE.</li>
* <li><b>EBADF</b>: The fd argument is not a valid file descriptor or or the underlying file system does not support
* this operation.</li>
* <li><b>EAGAIN</b>: The file list is NULL.</li>
* <li><b>EACCES</b>: Permission bits of the file mode do not permit the requested access,
* or search permission is denied on a component of the path prefix.</li>
* <li><b>ENOENT</b>: A directory component in pathname does not exist or is a dangling symbolic link.</li>
* <li><b>EEXIST</b>: The file/directory object is already exist.</li>
* <li><b>EIO</b>: An I/O error occurred while reading from or writing to a file system.</li>
* <li><b>EROFS</b>: The physical drive is write protected.</li>
* <li><b>ENOSPC</b>: The directory or file system that would contain the new file cannot be expanded,
* the file does not exist, and O_CREAT is specified.</li>
* <li><b>ENFILE</b>: The maximum allowable number of files is currently open in the system.</li>
* <li><b>ENOTEMPTY</b>: Directory not empty.</li>
* <li><b>EISDIR</b>: The named file is a directory.</li>
* <li><b>ENOTDIR</b>: A component of the path prefix names an existing file that is neither a directory nor a symbolic
* link to a directory; or the path argument resolves to a non-directory file.</li>
* <li><b>EPERM</b>: Operation not permitted or access denied due to prohibited access or directory full.</li>
* <li><b>EBUSY</b>: The operation is rejected according to the file sharing policy.</li>
* </ul>
*
* @par Dependency:
* <ul><li>fcntl.h</li></ul>
* @see None
* @since Huawei LiteOS V100R001C00
*/
extern int fallocate(int fd, int mode, off_t offset, off_t len);
extern int posix_fadvise(int, off_t, off_t, int);
extern int posix_fallocate(int, off_t, off_t);
#endif

/**
* @ingroup fcntl
*
* @par Description:
* The fallocate() function shall ensure that any required storage for regular file data starting at offset and
* continuing for len bytes is allocated on the file system storage media.
* @param fd     [IN] File descriptor.
* @param mode   [IN] Extend size.
* @param offset [IN] File offset.
* @param len    [IN] The length starting from the file offset.
* @attention
* <ul>
* <li>None.</li>
* </ul>
*
* @retval #0  Upon successful completion.
* @retval #-1 Failed and set errno to indicate the error.
*
* @par Errors
* <ul>
* <li><b>EINVAL</b>: The len argument or the offset argument is less than zero or greater than INT_MAX,
* or extend size is not equal to FALLOC_FL_KEEP_SIZE.</li>
* <li><b>EBADF</b>: The fd argument is not a valid file descriptor or or the underlying file system does not support
* this operation.</li>
* <li><b>EAGAIN</b>: The file list is NULL.</li>
* <li><b>EACCES</b>: Permission bits of the file mode do not permit the requested access,
* or search permission is denied on a component of the path prefix.</li>
* <li><b>ENOENT</b>: A directory component in pathname does not exist or is a dangling symbolic link.</li>
* <li><b>EEXIST</b>: The file/directory object is already exist.</li>
* <li><b>EIO</b>: An I/O error occurred while reading from or writing to a file system.</li>
* <li><b>EROFS</b>: The physical drive is write protected.</li>
* <li><b>ENOSPC</b>: The directory or file system that would contain the new file cannot be expanded,
* the file does not exist, and O_CREAT is specified.</li>
* <li><b>ENFILE</b>: The maximum allowable number of files is currently open in the system.</li>
* <li><b>ENOTEMPTY</b>: Directory not empty.</li>
* <li><b>EISDIR</b>: The named file is a directory.</li>
* <li><b>ENOTDIR</b>: A component of the path prefix names an existing file that is neither a directory nor a symbolic
* link to a directory; or the path argument resolves to a non-directory file.</li>
* <li><b>EPERM</b>: Operation not permitted or access denied due to prohibited access or directory full.</li>
* <li><b>EBUSY</b>: The operation is rejected according to the file sharing policy.</li>
* </ul>
*
* @par Dependency:
* <ul><li>fcntl.h</li></ul>
* @see None
* @since Huawei LiteOS V100R001C00
*/
extern int fallocate64(int fd, int mode, off64_t offset, off64_t len);
extern int posix_fadvise64(int, off64_t, off64_t, int);
extern int posix_fallocate64(int, off64_t, off64_t);

extern int __open_2(const char*, int);
extern int __open_real(const char*, int, ...) __RENAME(open);
extern int __openat_2(int, const char*, int);
extern int __openat_real(int, const char*, int, ...) __RENAME(openat);
__errordecl(__creat_missing_mode, "called with O_CREAT, but missing mode");
__errordecl(__creat_too_many_args, "too many arguments");

#if defined(__BIONIC_FORTIFY)

#if !defined(__clang__)

__BIONIC_FORTIFY_INLINE
int open(const char* pathname, int flags, ...) {
    if (__builtin_constant_p(flags)) {
        if ((flags & O_CREAT) && __builtin_va_arg_pack_len() == 0) {
            __creat_missing_mode();  // compile time error
        }
    }

    if (__builtin_va_arg_pack_len() > 1) {
        __creat_too_many_args();  // compile time error
    }

    if ((__builtin_va_arg_pack_len() == 0) && !__builtin_constant_p(flags)) {
        return __open_2(pathname, flags);
    }

    return __open_real(pathname, flags, __builtin_va_arg_pack());
}

__BIONIC_FORTIFY_INLINE
int openat(int dirfd, const char* pathname, int flags, ...) {
    if (__builtin_constant_p(flags)) {
        if ((flags & O_CREAT) && __builtin_va_arg_pack_len() == 0) {
            __creat_missing_mode();  // compile time error
        }
    }

    if (__builtin_va_arg_pack_len() > 1) {
        __creat_too_many_args();  // compile time error
    }

    if ((__builtin_va_arg_pack_len() == 0) && !__builtin_constant_p(flags)) {
        return __openat_2(dirfd, pathname, flags);
    }

    return __openat_real(dirfd, pathname, flags, __builtin_va_arg_pack());
}

#endif /* !defined(__clang__) */

#endif /* defined(__BIONIC_FORTIFY) */


#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus */
#endif /* __cplusplus */

#endif /* _FCNTL_H */
